﻿using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using Serilog.Sinks.File;
using ShanNiang.Hosting.Common;
using ShanNiang.Hosting.Enumerate;
using System.IO;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;

namespace ShanNiang.Hosting
{
    public static class HostingExtensions
    {
        private const string APPSETTINGS = "appsettings";
        private const string JSON = "json";
        private const string DOTNET_ENVIRONMENT = "DOTNET_ENVIRONMENT";
        public static void UseConfiguration(this IConfigurationBuilder builder)
        {
            builder.SetBasePath(Environment.CurrentDirectory);
            string defaultConfigFile = $"{APPSETTINGS}.{JSON}";
            if (File.Exists(Path.Combine(Environment.CurrentDirectory, defaultConfigFile)))
            {
                builder.AddJsonFile(defaultConfigFile);
            }
            string? entryName = null;

            var assembly = Assembly.GetEntryAssembly();
            if (assembly != null)
            {
                entryName = $"{assembly.GetName().Name}";

            }
            if (entryName != null)
            {
                var entryNameConfigFile = $"{entryName}.{JSON}";
                if (File.Exists(Path.Combine(Environment.CurrentDirectory, entryNameConfigFile)))
                {
                    builder.AddJsonFile(entryNameConfigFile);
                }
            }
            var env = GetEnvName();

            string defutEnvConfigFile = $"{APPSETTINGS}.{env}.{JSON}";
            string entryNameEnvConfigFile = $"{entryName}.{env}.{JSON}";
            if (File.Exists(Path.Combine(Environment.CurrentDirectory, defutEnvConfigFile)))
            {
                builder.AddJsonFile(defutEnvConfigFile);
            }
            if (File.Exists(Path.Combine(Environment.CurrentDirectory, entryNameEnvConfigFile)))
            {
                builder.AddJsonFile(entryNameEnvConfigFile);
            }
        }
        public static IServiceCollection ConfigureServices(HostBuilderContext context, IServiceCollection services, Assembly windowsAssembly, Assembly serviceAssembly)
        {
            var configuration = context.Configuration;
            services.AddLocalWindows(configuration, windowsAssembly);
            services.AddLocalServices(configuration, serviceAssembly);
            services.AddLocalUserControls(configuration, windowsAssembly);
            //services.Configure<AutoUpdateConfig>(configuration.GetSection("AutoUpdateConfig"));
            return services;
        }
        /// <summary>
        /// 添加本地窗体
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        /// <param name="assembly"></param>
        /// <returns></returns>
        public static IServiceCollection AddLocalWindows(this IServiceCollection services, IConfiguration configuration, Assembly assembly)
        {
            return services.AddLocalCostomServices(configuration, assembly, typeof(Window));
        }
        /// <summary>
        /// 添加本地服务
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        /// <param name="assembly"></param>
        /// <returns></returns>
        public static IServiceCollection AddLocalServices(this IServiceCollection services, IConfiguration configuration, Assembly assembly)
        {
            return services.AddLocalCostomServices(configuration, assembly, typeof(LocalService));
        }
        /// <summary>
        /// 添加本地用户控件
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        /// <param name="assembly"></param>
        /// <returns></returns>
        public static IServiceCollection AddLocalUserControls(this IServiceCollection services, IConfiguration configuration, Assembly assembly)
        {
            return services.AddLocalCostomServices(configuration, assembly,typeof(UserControl));
        }
        /// <summary>
        /// 添加本地定制服务
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        /// <param name="baseType"></param>
        /// <param name="assembly"></param>
        /// <returns></returns>
        public static IServiceCollection AddLocalCostomServices(this IServiceCollection services, IConfiguration configuration, Assembly assembly, Type baseType)
        {
            var types = assembly.GetTypes().Where(t => IsInheriteFrom(t, baseType)).ToArray(); 
            foreach (var type in types)
            {
                if (!type.IsAbstract)
                {
                    AddService(services, type);
                }
            }
            return services;
        }
        /// <summary>
        /// 获取运行环境值
        /// </summary>
        /// <returns></returns>
        public static string GetEnvName()
        {
            var env =Environment.GetEnvironmentVariable(DOTNET_ENVIRONMENT);
            if (!string.IsNullOrEmpty(env))
            {
                return env;
            }
            return env = Environments.Production;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <param name="baseType"></param>
        /// <returns></returns>
        private static bool IsInheriteFrom(Type type, Type baseType)
        {
            if (type.BaseType == null)
            {
                return false;
            }
            if (type.BaseType == baseType)
            {
                return true;
            }
            return IsInheriteFrom(type.BaseType, baseType);
        }

        private static void AddService(this IServiceCollection services, Type implementation)
        {
            Type? interfaceType;

            var lifetime = implementation.GetCustomAttribute<DILifetimeAttribute>();
            if (lifetime == null)
            {
                lifetime = new DILifetimeAttribute(LifetimeType.Singleton);
            }
            if (lifetime.InterfaceType == null)
            {
                interfaceType = implementation.GetInterface($"I" + implementation.Name, true);
            }
            else
            {
                interfaceType = lifetime.InterfaceType;
            }
            if (interfaceType != null)
            {
                switch (lifetime.LifetimeType)
                {
                    case LifetimeType.Transient:
                        services.AddTransient(interfaceType, implementation);
                        break;
                    case LifetimeType.Scoped:
                        services.AddScoped(interfaceType, implementation);
                        break;
                    case LifetimeType.Singleton:
                        services.AddSingleton(interfaceType, implementation);
                        break;
                }
            }
            else
            {
                switch (lifetime.LifetimeType)
                {
                    case LifetimeType.Transient:
                        services.AddTransient(implementation);
                        break;
                    case LifetimeType.Scoped:
                        services.AddScoped(implementation);
                        break;
                    case LifetimeType.Singleton:
                        services.AddSingleton(implementation);
                        break;
                }
            }
        }
    }
}
